import requests
import time, json
from hashlib import md5
import os
from apscheduler.schedulers.blocking import BlockingScheduler
from multiprocessing import Process
requests.packages.urllib3.disable_warnings()

"""
从第一页开始获取周围的商铺，知道获取到的商铺为空停止
将获取商铺从session中摘出，以无登陆账号的状态去获取，防止风控
"""    
def get_food_list(jd,wd):
    headers = {
        "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3",
        "Accept-Language": "zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7",
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36 Edg/114.0.1823.82",
        "Origin" : "https://h5.fantengteng.com",
        "Referer" : "https://h5.fantengteng.com/",
        "Api-Key" : "",
        "Api-Space" : "",
        "Api-Time" : "",
        "App-Version" : "",
        "Form-Type" : "wechat",
        "Content-Type" : "application/json",
        "sec-fetch-site": "same-site",
        "sec-fetch-mode": "cors",
        "sec-fetch-dest": "empty",
    }
    headers["Api-Time"]=str(int(time.time()))
    headers["Api-Key"]=md5((headers["Api-Time"]+"wffik0k8kt2yykdh").encode("utf-8")).hexdigest()
    headers["Api-Space"]=json.loads(requests.post(url="https://api.fantengteng.com/api/index", headers=headers, verify=False).content)["data"]["login_key"]
    food_list=[]
    for x in range(1,10):
        parm = {
            "can_buy": True,
            "cate": 0,
            "code": "双平台",
            "is_rebate": False,
            "keyword": "",
            "limit": 20,
            "location": wd+","+jd,
            "no_comment": False,
            "page": x,
            "sort": "all"
        }
        headers["Api-Time"]=str(int(time.time()))
        headers["Api-Key"]=md5((headers["Api-Time"]+"wffik0k8kt2yykdh").encode("utf-8")).hexdigest()
        jsons = requests.post(url="https://api.fantengteng.com/api/activitys", headers=headers,json=parm, verify=False)
        json_content=json.loads(jsons.content)
        food_list.extend(list(json_content["data"]))
        if len(json_content["data"])==0:
            break
    return food_list

"""
打印二维list
"""
def print_list_2d(list2):
    for i in range(len(list2)):
        for j in range(len(list2[i])):
            print(list2[i][j])

"""
打印一维list
"""
def print_list(list1):
    for i in range(len(list1)):
        print(list1[i])   
    
    
class ftt:   
    def __init__(self):
        self.is_login=False
        self.login_url = "https://api.fantengteng.com/api/login"
        self.food_list_url = "https://api.fantengteng.com/api/activitys"
        self.index_url = "https://api.fantengteng.com/api/index"
        self.s=requests.session()
        self.historyorder=[]
        self.coordinates={
            "1":"华源,39.881901,116.313454",
            "2":"国投,39.89108,116.323105",
            "3":"信通,39.980368,116.35572"
        }
        self.headers = {
            "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3",
            "Accept-Language": "zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7",
            "User-Agent": "Mozilla/5.0 (Linux; Android 12; M2007J3SC Build/SKQ1.211006.001; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/111.0.5563.116 Mobile Safari/537.36 XWEB/5175 MMWEBSDK/20230202 MMWEBID/1672 MicroMessenger/8.0.33.2320(0x28002137) WeChat/arm64 Weixin NetType/WIFI Language/zh_CN ABI/arm64",
            "Origin" : "https://h5.fantengteng.com",
            "Referer" : "https://h5.fantengteng.com/",
            "Api-Key" : "",
            "Api-Space" : "undefined",
            "Api-Time" : "",
            "App-Version" : "",
            "Form-Type" : "h5",
            "Content-Type" : "application/json",
            "sec-fetch-site": "same-site",
            "sec-fetch-mode": "cors",
            "sec-fetch-dest": "empty",
        }
        self.get_api_space()        
    
    """
    请求头有参数加密
    在每次请求的时候都需要重新设置时间戳和Api-Key
    否则服务器会返回请求超时
    """
    def set_time_and_key(self):
        self.headers["Api-Time"]=str(int(time.time()))
        self.headers["Api-Key"]=md5((self.headers["Api-Time"]+"wffik0k8kt2yykdh").encode("utf-8")).hexdigest()
    
    """
    在初始化的时候获取Api-Space
    将Api-Space加入到请求头后同一session中以后的请求中都不需要再次获取
    """    
    def get_api_space(self):
        self.set_time_and_key()
        jsons = self.s.post(url=self.index_url, headers=self.headers, verify=False)
        json_content=json.loads(jsons.content)
        self.headers["Api-Space"]=json_content["data"]["login_key"]

    """
    登录后获取token，有了token之后就可以创建订单了
    """
    def get_token(self,account,password):
        parm = {
            "account": account,
            "password": password,
            "client_id": ""
        }
        self.set_time_and_key()
        jsons = self.s.post(url=self.login_url, headers=self.headers,json=parm, verify=False)
        json_content=json.loads(jsons.content)
        print(json_content)
        if json_content["msg"] == "登录成功":
            self.is_login=True
            self.headers["Authori-Zation"]="Bearer "+json_content["data"]["token"]

    """
    通过商铺的sid获取商铺发布的订单
    """
    def get_id(self,sid):
        self.set_time_and_key()
        jsons = self.s.get(url=f"https://api.fantengteng.com/api/activity/detail?sid={sid}&eid=", headers=self.headers,verify=False)
        content_json = json.loads(jsons.content)
        if content_json["msg"]!="success":
            print(content_json)
            return False
        eidlist=list(content_json["data"]["list"])
        return eidlist

    """
    获取到eid之后通过eid创建订单
    """
    def create_order(self,eid):
        parm = {
            "eid": eid
        }
        self.set_time_and_key()
        jsons = self.s.post(url="https://api.fantengteng.com/api/order/create/", headers=self.headers,json=parm,verify=False)
        content_json=json.loads(jsons.content)
        for i in range(6):
            time.sleep(0.3)
            if content_json["msg"] == "订单创建成功":
                print("抢单成功："+str(content_json))
                return True
            elif content_json["msg"] == "订单已存在":
                return 300
            else:
                jsons = self.s.post(url="https://api.fantengteng.com/api/order/create/", headers=self.headers,json=parm,verify=False)
                content_json=json.loads(jsons.content)
                print(content_json)
    
    """
    因为有的商家固定时间才上架订单，所以需要提前一天拿到sid，然后在固定时间上架的时候根据sid抢订单
    """        
    def create_order_by_sid(self,sid):
        eid_list=self.get_id(sid)
        while eid_list==False:
            time.sleep(1)
            eid_list=self.get_id(sid)
        eid=""
        value=999
        for i in range(len(eid_list)):
            tmp=json.loads(str(eid_list[i]).replace("'", "\""))  
            if int(tmp["mark_amount"])-int(tmp["member_back_limit"]) < value:
                value=int(tmp["mark_amount"])-int(tmp["member_back_limit"])
                eid=tmp["id"]   
        self.create_order(eid)     
    
    """
    获取已经创建的订单
    """        
    def get_create_list(self):
        create_list=[]
        for x in range(1,10):
            self.set_time_and_key()
            jsons = self.s.get(url=f"https://api.fantengteng.com/api/order/list?page={x}&limit=10&type=1&all_data=1", headers=self.headers, verify=False)
            json_content=json.loads(jsons.content)
            create_list.extend(list(json_content["data"]["list"]))
            if len(json_content["data"]["list"])==0:
                break
        return create_list
    
    """
    保活cookie
    """        
    def keep_alive(self):
        print("运行了一次保活cookie")
        self.set_time_and_key()
        self.s.get(url="https://api.fantengteng.com/api/user?money=1", headers=self.headers,verify=False)
    
    """
    每天晚上12点整清除当天订单缓存
    """        
    def clear_historyorder(self):
        print("清除了当天的订单缓存")
        self.historyorder=[]
    
    """
    获取服务器时间，用于计算预约时间和服务器时间的差值
    """        
    def get_server_datetime(self,website,yy_time):
        jsons = self.s.get(url=website,verify=False)
        timestamp = jsons.headers['date']
        ltime = time.strptime(timestamp[5:25], "%d %b %Y %H:%M:%S")  
        webtime=time.mktime(ltime)+8*60*60
        print(yy_time-webtime)
        return yy_time-webtime
    
    """
    创建高返利订单
    """
    def auto_reservation(self,jd,wd,one,two,three):
        start=time.time() 
        print("此次检索开始时间：",time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(start)))
        shoplists = get_food_list(jd,wd)
        orderlists=[]
        for shop in shoplists:
            for order in shop:
                high = int(order['mark_amount'])
                low = int(order['member_back_limit'])
                work = order['is_business']
                number = order['remaining_count']
                if high>=30:
                    if (high - low > int(three) or work == 0 or number == 0) == False:
                        eidlist=self.get_id(order["sid"])
                        orderlists.extend(eidlist)
                        break
                elif high>=20 and high<30:
                    if (high - low > int(two) or work == 0 or number == 0) == False:
                        eidlist=self.get_id(order["sid"])
                        orderlists.extend(eidlist)
                        break
                elif high>=15 and high<20:
                    if (high - low > int(one) or work == 0 or number == 0) == False:
                        eidlist=self.get_id(order["sid"])
                        orderlists.extend(eidlist)
                        break
        print(f"未比对已创建的订单前共找到{len(orderlists)}个符合条件的订单！")
        if len(orderlists)==0:
            return
        neworders=[]
        for i in orderlists:
            if len(self.historyorder)==0:
                high = int(i['mark_amount'])
                low = int(i['member_back_limit'])
                if high>=30:
                    if not ((high - low > int(three)) or (i['remaining_count'] == 0) or (i["is_new_user_desc"]=="是")):
                        self.historyorder.append(i)
                        neworders.append(i)
                elif high>=20 and high<30:
                    if not ((high - low > int(two)) or (i['remaining_count'] == 0) or (i["is_new_user_desc"]=="是")):
                        self.historyorder.append(i)
                        neworders.append(i)
                elif high>=15 and high<20:
                    if not ((high - low > int(one)) or (i['remaining_count'] == 0) or (i["is_new_user_desc"]=="是")):
                        self.historyorder.append(i)
                        neworders.append(i)
            else:
                is_eligibility=True
                for j in self.historyorder:
                    high = int(i['mark_amount'])
                    low = int(i['member_back_limit'])
                    if high>=30:
                        if ((i["platform_name"] == j["platform_name"]) and ((i["is_ele"]==j["is_ele"]) or (i["is_mt"]==j["is_mt"]))) or (high - low > int(three)) or (i['remaining_count'] == 0) or (i["is_new_user_desc"]=="是"):
                            is_eligibility=False
                            break
                    elif high>=20 and high<30:
                        if ((i["platform_name"] == j["platform_name"]) and ((i["is_ele"]==j["is_ele"]) or (i["is_mt"]==j["is_mt"]))) or (high - low > int(two)) or (i['remaining_count'] == 0) or (i["is_new_user_desc"]=="是"):
                            is_eligibility=False
                            break
                    elif high>=15 and high<20:
                        if ((i["platform_name"] == j["platform_name"]) and ((i["is_ele"]==j["is_ele"]) or (i["is_mt"]==j["is_mt"]))) or (high - low > int(one)) or (i['remaining_count'] == 0) or (i["is_new_user_desc"]=="是"):
                            is_eligibility=False
                            break
                if is_eligibility==True:
                    self.historyorder.append(i)
                    neworders.append(i)
        print(f"比对后共找到{len(neworders)}个符合条件的订单！")
        end=time.time()
        print("此次检索用时：",end-start)
        if len(neworders)==0:
            return
        for u in neworders:
            print("此次抢单的商店有："+u["platform_name"])
            Process(target=self.create_order,args=(u["id"],)).start()
        print("抢单完成后的历史缓存有：")
        for x in self.historyorder:
            print(x)
        
    """
    选择常见地址
    """
    def select_coordinate(self):
        w=""
        j=""
        print("1、选择常用地址")
        print("2、输入经纬度")
        x=input()
        if x=="1":
            for i in self.coordinates:
                print(f'{self.coordinates[i]}')
            num=input("请按照顺序输入1，2，3选择地址：")
            lists=self.coordinates[num].split(",")
            w=lists[1]
            j=lists[2]
        elif x=="2": 
            while w=="":
                w = input("请输入纬度：")
            while j=="":
                j = input("请输入经度：")
        return [j,w]
        
    """
    选择功能
    """
    def select(self,num):
        match num:
            case "1":
                lists=self.select_coordinate()
                list2=get_food_list(lists[0],lists[1])
                print_list_2d(list2)
            case "2":
                sid=""
                while sid=="":
                    sid = input("请输入抓取到的sid：")
                list1=self.get_id(sid)
                print_list(list1)
            case "3":
                eid=""
                while eid=="":
                    eid = input("请输入抓取到的eid：")
                yy_time=""
                while yy_time=="":
                    yy_time = input("请输入预约时间戳：")
                time.sleep(self.get_server_datetime('https://time.tianqi.com',float(yy_time))-2.0)
                self.create_order(eid)
            case "4":
                eid=""
                while eid=="":
                    eid = input("请输入抓取到的eid：")
                self.create_order(eid)
            case "5":
                sid=""
                while sid=="":
                    sid = input("请输入抓取到的sid：")
                yy_time=""
                while yy_time=="":
                    yy_time = input("请输入预约时间戳：")
                time.sleep(self.get_server_datetime('https://time.tianqi.com',float(yy_time))-6.0)
                self.create_order_by_sid(sid)
            case "6":
                sid=""
                while sid=="":
                    sid = input("请输入抓取到的sid：")
                yy_time=""
                self.create_order_by_sid(sid)
            case "7":
                lists=self.select_coordinate()
                one = ""
                while one == "":
                    one = input("请输入订单实付金额15-20（不包括20）的订单，真实支付金额的上限：")
                two = ""
                while two == "":
                    two = input("请输入订单实付金额20-30（不包括30）的订单，真实支付金额的上限：")
                three = ""
                while three == "":
                    three = input("请输入订单实付金额30以上的订单，真实支付金额的上限：")
                scheduler = BlockingScheduler(timezone="Asia/Shanghai")
                scheduler.add_job(self.auto_reservation, 'cron', minute='*', second="2", args=[lists[0], lists[1], one, two, three])
                scheduler.add_job(self.keep_alive, 'cron', minute='*/15')
                scheduler.add_job(self.clear_historyorder, 'cron', day='*')
                scheduler.start()
            case "8":
                lists=self.get_create_list()
                print_list(lists)
            case "999":
                account=""
                while account=="":
                    account = input("请输入账号：")
                password=""
                while password=="":
                    password = input("请输入密码：")
                self.get_token(account,password)
            case "0":
                print("按任意键退出程序")
                os.system("pause")
                exit()
            case _:
                return
                
if __name__ == "__main__":
    f=ftt()
    while True:
        if f.is_login==False:
            print("1、获取周围的商铺")
            print("999、登录账号获取更多功能")
            print("0、退出程序")
            num = input("请选择要执行的功能：")
            f.select(num)
        else:
            print("1、获取周围的商铺")
            print("2、通过sid获取商铺发布的订单")
            print("3、通过eid预约订单")
            print("4、通过eid立即创建订单")
            print("5、通过sid预约订单")
            print("6、通过sid立即创建订单")
            print("7、定时监控抢单")
            print("8、获取已经创建的订单")
            print("0、退出程序")
            num = input("请选择要执行的功能：")
            f.select(num)



